#include "skilltablemodel.h"


#include <dtwentymodel.h>
#include <characterclass.h>
#include <skill.h>


#include <QDebug>
#include <QTimer>
#include <QStringList>

SkillTableModel::SkillTableModel(QObject *parent) :
    QAbstractTableModel(parent)
{
}

void SkillTableModel::setCampaign(Campaign *campaign)
{
    if (m_campaign.data() == campaign)
    {
        return;
    }

    beginResetModel();
    m_skills = 0;
    m_characterClasses = 0;
    m_campaign = campaign;

    if (!m_campaign.isNull())
    {
        m_skills = m_campaign->findChild<Skills*>(QString(), Qt::FindDirectChildrenOnly);
        m_characterClasses = m_campaign->findChild<CharacterClasses*>(QString(), Qt::FindDirectChildrenOnly);
    }
    endResetModel();
}

int SkillTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    if (!ready())
    {
        return 0;
    }


    QList<Skill*> skillList = m_skills->findChildren<Skill*>(QString(), Qt::FindDirectChildrenOnly);
    return skillList.count();
}


int SkillTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    if (!ready())
    {
        return 0;
    }

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    return characterClassList.count() + 1;
}

QVariant SkillTableModel::data(const QModelIndex &index, int role) const
{
    if (!ready() || !index.isValid())
    {
        return QVariant();
    }

    if (index.column() == 0)
    {
        if (role != Qt::DisplayRole)
        {
            return QVariant();
        }

        QList<Skill*> skillList = m_skills->findChildren<Skill*>(QString(), Qt::FindDirectChildrenOnly);
        if (index.row() < 0 || index.row() >= skillList.count())
        {
            return tr("[Invalid Row]");
        }

        return skillList.at(index.row())->name();
    }

    if (role != Qt::CheckStateRole)
    {
        return QVariant();
    }


    QModelIndex skillIndex = index.sibling(index.row(), 0);

    if (!skillIndex.isValid())
    {
        qDebug() << Q_FUNC_INFO << "Skill Source is invalid";
        return QVariant();
    }

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    int at = index.column()-1;

    if (at < 0 || at >= characterClassList.count())
    {
        return tr("[Invalid Column]");
    }

    CharacterClass* characterClass = characterClassList.at(at);
    if (!characterClass)
    {
        qDebug() << Q_FUNC_INFO << "Class Pointer is invalid";
        return QVariant();
    }

    foreach (Skill* skill, characterClass->findChildren<Skill*>())
    {
        if (skill->name() == skillIndex.data().toString())
        {
            return Qt::Checked;
        }
    }

    return Qt::Unchecked;

}

QVariant SkillTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (!ready())
    {
        return QVariant();
    }

    if (orientation == Qt::Vertical)
    {
        return QAbstractTableModel::headerData(section, orientation, role);
    }

    if (role != Qt::DisplayRole && role != Qt::ToolTipRole && role != Qt::StatusTipRole)
    {
        return QVariant();
    }

    if (section == 0)
    {
        return tr("Skill");
    }

    int at = section-1;

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (at < 0 || at >= characterClassList.count())
    {
        return tr("[Invalid Section]");
    }

    CharacterClass* characterClass = characterClassList.at(at);
    if (!characterClass)
    {
        return tr("[Invalid data]");
    }

    QList<const Skill*> classSkills = characterClass->findChildren<const Skill*>();
    int num = 0;
    int craft = 0;
    int know = 0;
    int perf = 0;
    int prof = 0;
    foreach (const Skill* skill, classSkills)
    {
        if (skill->name().startsWith("craft", Qt::CaseInsensitive))
        {
            craft++;
            continue;
        }

        if (skill->name().startsWith("knowledge", Qt::CaseInsensitive))
        {
            know++;
            continue;
        }

        if (skill->name().startsWith("peform", Qt::CaseInsensitive))
        {
            perf++;
            continue;
        }

        if (skill->name().startsWith("profession", Qt::CaseInsensitive))
        {
            prof++;
            continue;
        }

        num++;
    }

    if (role == Qt::DisplayRole)
    {
        QStringList parts = characterClass->name().split(" ");
        QString abbr;
        if (parts.count() == 0)
        {
            abbr = tr("[Not Set]");
        }
        else if (parts.count() == 1)
        {
            abbr = parts.first().left(3);
        }
        else
        {
            abbr = parts.value(0).left(1) + parts.value(1).left(2);
        }

        num = num + bool(craft) + bool(know) + bool(perf) + bool(prof);
//        QString abbr = QString("%1%2").arg(characterClass->name().left(1)).arg(characterClass->name().right(2));

        return QString("%1\n(%2)").arg(abbr).arg(num);
    }

    return QString("Cr: %1, Kn: %2, Pe: %3, Pr: %4, Ot: %5, Total: %6")
            .arg(craft)
            .arg(know)
            .arg(perf)
            .arg(prof)
            .arg(num)
            .arg(classSkills.count());
}

bool SkillTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!ready() || !index.isValid())
    {
        return false;
    }

    QList<Skill*> skillList = m_skills->findChildren<Skill*>(QString(), Qt::FindDirectChildrenOnly);
    if (index.row() < 0 || index.row() >= skillList.count())
    {
        return false;
    }

    Skill* skill = skillList.at(index.row());
    if (!skill)
    {
        return false;
    }

    if (index.column() == 0)
    {
        if (role != Qt::EditRole) return false;

        skill->setName(value.toString());
        emit dataChanged(index, index);
        return true;
    }

    if (role != Qt::CheckStateRole)
    {
        qDebug() << "class skill edit: not check state role";

        return false;
    }

    int at = index.column()-1;

    QList<CharacterClass*> characterClassList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (at < 0 || at >= characterClassList.count())
    {
        return false;
    }

    CharacterClass* characterClass = characterClassList.at(at);

    Skills* classSkills = characterClass->findChild<Skills*>(QString(), Qt::FindDirectChildrenOnly);
    QList<Skill*> classSkillList = classSkills->findChildren<Skill*>(QString(), Qt::FindDirectChildrenOnly);

//    qDebug() << "Searching class skill" << skillSource.data().toString() << "from" << characterClass->name() << classSkillList.count();

    foreach (Skill* classSkill, classSkillList)
    {
        // class skill exists
//        qDebug() << "Compare" << skill->name() << "->" << skillSource.data().toString();
        if (classSkill->name() != skill->name())
        {
            continue;
        }

        if (value.toInt() == Qt::Checked)
        {
            qDebug() << "Failed to remove class skill, value is 'checked'";
            return false;
        }

//        qDebug() << "Removing class skill"  << skill->name() << "from" << characterClass->name();

        classSkill->setParent(0);
        classSkill->deleteLater();

        emit dataChanged(index, index);
        emit headerDataChanged(Qt::Horizontal, index.column(), index.column());

        return true;
    }

    if (value.toInt() == Qt::Unchecked)
    {
        return false;
    }

//    qDebug() << "Adding class skill" << characterClass->name() << skillSource.data().toString();

    Skill* classSkill = qobject_cast<Skill*>(classSkills->newChild());
    classSkill->setReferenceItem(skill);

    emit dataChanged(index, index);
    emit headerDataChanged(Qt::Horizontal, index.column(), index.column());

    return true;
}

Qt::ItemFlags SkillTableModel::flags(const QModelIndex &index) const
{
    if (!ready() || !index.isValid())
    {
        qDebug() << Q_FUNC_INFO << "Invalid index";
        return QAbstractItemModel::flags(index);
    }

    if (index.column() == 0)
    {
        return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
    }

    return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable;
}

bool SkillTableModel::ready() const
{
    return (!m_campaign.isNull() && !m_characterClasses.isNull() && !m_skills.isNull());
}


